/*
 * @Author: Drc
 * @Date: 2021-06-07 11:41:41
 * @LastEditTime: 2021-09-24 10:30:47
 * @LastEditors: Drc
 */

import {AppState, AppStateStatus, DeviceEventEmitter} from 'react-native'
import Config from '@path/config/index'
import store from '@path/redux'
import Crypto from '@path/config/crypto'

type WSType = 'heartbeat'

export class WSAction {
  type: WSType
  param: Object
  constructor(type: WSType, param: Object = {}) {
    this.type = type
    this.param = {timestamp: Math.round(new Date().getTime() / 1000), ...param}
  }
}

interface WSMessage {
  type: WSType
  code: number
  data: Object
  msg: string
}

interface WSListener {
  type: WSType
  callback: (res: WSMessage) => any
}

enum LogLevel {
  none = 0,
  normal = 1,
  all = 2,
}

/**
 * WebSocket管理类
 */
export default class WSDao {
  static ws?: WebSocket
  static pingTimer: any
  static pingDuration = 5000
  static isStopWS = false
  static reConnectDuration = 5000
  static logLevel: LogLevel = LogLevel.normal
  static reConnectTimer: any

  //初始化
  static init() {
    const address = `${Config.WS_HOST}?token=${store.getState().user.token}`
    this.ws = new WebSocket(address)
    this.isStopWS = false
    this.ws.onopen = () => {
      this._handleLog(LogLevel.normal, '【WS】连接成功:', address)
      this.pingTimer = setInterval(() => {
        this.send(new WSAction('heartbeat'))
      }, this.pingDuration)
    }
    this.ws.onclose = (e) => {
      this._handleLog(LogLevel.normal, '【WS】连接关闭', e)
      this.ws = undefined
      this._stopPing()
      if (this.isStopWS) {
        return
      }

      this.reConnectTimer = setTimeout(() => {
        this.init()
      }, this.reConnectDuration)
    }
    this.ws.onmessage = (e) => {
      try {
        let decryptData = Crypto.AES.decrypt(e.data)
        let data: WSMessage = JSON.parse(decryptData)
        this._handleLog(data?.type === 'heartbeat' ? LogLevel.all : LogLevel.normal, '【WS】接受消息', data)
        if (data?.msg) {
          store.dispatch.utils.showToast({text: data.msg})
        }
        DeviceEventEmitter.emit(data.type, data)
      } catch (error) {
        this._handleLog(LogLevel.normal, '【WS】接受消息出错', error)
      }
    }
    this.ws.onerror = (e) => {
      this._handleLog(LogLevel.normal, '【WS】出错', e.message)
    }
    AppState.removeEventListener('change', this._handleAppState)
    AppState.addEventListener('change', this._handleAppState)
  }

  //发送消息
  static send(msg: WSAction) {
    try {
      if (this.ws?.readyState === 1) {
        const formatMsg = JSON.stringify(msg)
        this._handleLog(LogLevel.normal, '【WS】发送消息 加密前:', msg)
        const encryptMsg = Crypto.AES.encrypt(formatMsg)
        this._handleLog(LogLevel.all, '【WS】发送消息 加密后:', encryptMsg)
        this.ws?.send(encryptMsg)
      }
    } catch (error) {}
  }

  //添加监听
  static addListener(listener: WSListener) {
    return DeviceEventEmitter.addListener(listener.type, listener.callback)
  }

  //断开连接
  static disconnect() {
    this.isStopWS = true
    clearTimeout(this.reConnectTimer)
    this.reConnectTimer = null
    this._stopPing()
    this.ws?.close()
  }

  //停止发送心跳包
  static _stopPing() {
    if (this.pingTimer) {
      clearInterval(this.pingTimer)
      this.pingTimer = null
    }
  }

  //控制打印
  static _handleLog(logLevel: LogLevel, message?: any, ...optionalParams: any[]) {
    if (this.logLevel >= logLevel) {
      console.log(message, ...optionalParams)
    }
  }

  static _handleAppState(e: AppStateStatus) {
    switch (e) {
      case 'active':
        WSDao.init()
        break
      case 'background':
        WSDao.disconnect()
    }
  }
}
